package http;

import login.GetLogineUserServlet;
import login.LoginServlet;

import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class Tomcat {

    public static void main(String[] args) throws IOException {
        Tomcat t = new Tomcat();
        t.startup();
    }

    public boolean runing = true;
    public static  String webRootPath = "D:\\soundcode\\idea_workspaces\\web二周目_项目\\web";

    //servlet 容器 在配置情况下 servlet 也可以在服务器启动时 加载到容器中 实现简单
    private static Map<String, HttpServlet> servletMap = new HashMap<>();
    //会话容器
    private Map<String, HttpSession> sessionMap = new HashMap<>();

    public void startup() throws IOException {

        //初始化Servlet 容器
        initServletContainer();

        runing = true;
        ServerSocket server = new ServerSocket(8080);
        while(runing){
            System.out.println("========服务器监听端口8080========");
            Socket socket = server.accept();
            new Thread(() -> {
                try {
                    InputStream inputStream = socket.getInputStream();
                    OutputStream outputStream = socket.getOutputStream();

                    //构建请求对象
                    HttpServletRequest request = new HttpServletRequest(inputStream);
                    //构建响应对象
                    HttpServletResponse response = new HttpServletResponse(outputStream, request);

                    /*1:判断请求中是否包含 会话ID
                    *  1)cookie 方式（默认方式）
                    *  2)地址编码，写入会话ID，从地址中获取
                    *  3)隐藏域提交会话 ID
                    * */
                    Cookie[] cookies = request.getCookies();
                    String  id = null;
                    if(cookies != null){
                        for (Cookie cookie :  cookies ) {
                            if("JSESSIONID".equals(cookie.getName())){
                                id = cookie.getValue();
                            }
                        }
                    }
                    HttpSession session = sessionMap.get(id);

                    if(session != null){
                        //2.如果容器中包含，则根据ID获取相应的会话对象，设置到请求对象中
                        request.setSession(session);
                    }else{
                        //3.如果不包含则创建对象
                        session =  new HttpSession();
                        //4.将会话存入到会话容器中
                        sessionMap.put(session.getId(),session);
                        //5.将会话存入请求对象
                        request.setSession(session);
                        Cookie cookie = new Cookie("JSESSIONID", session.getId());
                        response.addCookie(cookie);
                    }

                    //判断当前的请求是动态请求还是静态请求
                    if(isDynamic(request)){
                        HttpServlet servlet = servletMap.get(request.getRequestURI());
                        //调用相应servlet的 service方法
                        servlet.service(request, response);
                    }
                    //输出内容
                    response.flushBuffer();
                    socket.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }).start();
        }
    }

    public static boolean isDynamic(HttpServletRequest request) {
        String uri = request.getRequestURI();
        return servletMap.containsKey(uri);
    }

    private void initServletContainer(){
        //扫描所有标注了 WebServlet 注解的类 扫描过程省略
        HttpServlet[] servlets = {
                new HelloServlet(),
                new RedirectSrevlet(),
                new CookieServlet(),
                new SessionServlet(),
                new LoginServlet(),
                new GetLogineUserServlet(),
        };

        //读取配置，将seevlet 实例与地址绑定
        for (HttpServlet servlet: servlets) {
            //JAVA 反射
            WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
            //servlet 的地址可以有多个
            String[] paths = ws.value();
            for (String path : paths) {
                servletMap.put(path, servlet);
                //执行生命周期方法 init
                servlet.init();
            }
        }
    }

    public void shutdown(){
        System.out.println("停止服务器");
        runing = false;
    }
}
